package com.yanliang.server;

import com.yanliang.model.*;
import com.yanliang.servlet.HttpServlet;
import com.yanliang.utils.HttpProtocolUtil;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * Mincat 的主类
 * @author yanliang
 * @date 5/10/20202:24 PM
 */
public class Bootstrap {

	/**定义socket监听的端口号*/
	private int port = 8080;

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}
//
//	/**
//	 * 完成Minicat 1.0版本
//	 * 需求：浏览器请求http://localhost:8080,返回一个固定的字符串到页面"Hello Minicat!"
//	 * @throws IOException
//	 */
//	public void start1() throws IOException {
//
//		ServerSocket serverSocket = new ServerSocket(port);
//		System.out.println("=====>>>Minicat start on port：" + port);
//
//		// 阻塞式监听 port
//		while(true) {
//            Socket socket = serverSocket.accept();
//            // 有了socket，接收到请求，获取输出流
//			OutputStream outputStream = socket.getOutputStream();
//			String data = "Hello Minicat!";
//			String responseText = HttpProtocolUtil.getHttpHeader200(data.getBytes().length) + data;
//			outputStream.write(responseText.getBytes());
//			socket.close();
//        }
//	}
//
//	/**
//	 * 完成Minicat 2.0版本
//	 * 需求：封装Request和Response对象，返回html静态文件
//	 */
//	public void start2() throws IOException {
//		ServerSocket serverSocket = new ServerSocket(port);
//		System.out.println("=====>>>Minicat start on port：" + port);
//
//        while(true) {
//            Socket socket = serverSocket.accept();
//            InputStream inputStream = socket.getInputStream();
//
//            // 封装Request对象和Response对象
//            Request request = new Request(inputStream);
//            Response response = new Response(socket.getOutputStream());
//
//            response.outputHtml(request.getUrl());
//            socket.close();
//        }
//	}
//
//	/**
//	 * 完成Minicat 3.0版本
//	 * 需求：可以请求动态资源（Servlet）
//	 */
//	public void start3() throws Exception {
//
//		// 加载解析相关的配置，web.xml
//		loadServlet();
//
//		ServerSocket serverSocket = new ServerSocket(port);
//		System.out.println("=====>>>Minicat start on port：" + port);
//
//		while(true) {
//			Socket socket = serverSocket.accept();
//			InputStream inputStream = socket.getInputStream();
//
//			// 封装Request对象和Response对象
//			Request request = new Request(inputStream);
//			Response response = new Response(socket.getOutputStream());
//
//			// 静态资源处理
//			if(servletMap.get(request.getUrl()) == null) {
//				response.outputHtml(request.getUrl());
//			}else{
//				// 动态资源servlet请求
//				HttpServlet httpServlet = servletMap.get(request.getUrl());
//				httpServlet.service(request,response);
//			}
//			socket.close();
//		}
//	}
//
//	/**
//	 * 多线程改造
//	 */
//	public void start4() throws Exception {
//
//		// 加载解析相关的配置，web.xml
//		loadServlet();
//
//		// 定义一个线程池
//		int corePoolSize = 10;
//		int maximumPoolSize =50;
//		long keepAliveTime = 100L;
//		TimeUnit unit = TimeUnit.SECONDS;
//		BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(50);
//		ThreadFactory threadFactory = Executors.defaultThreadFactory();
//		RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
//
//
//		ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
//				corePoolSize,
//				maximumPoolSize,
//				keepAliveTime,
//				unit,
//				workQueue,
//				threadFactory,
//				handler
//		);
//
//		ServerSocket serverSocket = new ServerSocket(port);
//		System.out.println("=====>>>Minicat start on port：" + port);
//
//
//		System.out.println("=========>>>>>>使用线程池进行多线程改造");
//        /*
//            多线程改造（使用线程池）
//         */
//		while(true) {
//
//			Socket socket = serverSocket.accept();
//			RequestProcessor requestProcessor = new RequestProcessor(socket,servletMap);
////			requestProcessor.start();
//			threadPoolExecutor.execute(requestProcessor);
//		}
//
//	}
//
//	/**
//	 * 加载解析web.xml，初始化Servlet
//	 */
//	private Map<String,HttpServlet> servletMap = new HashMap<String,HttpServlet>();
//
//	private void loadServlet() {
//		InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("web.xml");
//		SAXReader saxReader = new SAXReader();
//
//		try {
//			Document document = saxReader.read(resourceAsStream);
//			Element rootElement = document.getRootElement();
//
//			List<Element> selectNodes = rootElement.selectNodes("//servlet");
//			for (int i = 0; i < selectNodes.size(); i++) {
//				Element element =  selectNodes.get(i);
//				Element servletnameElement = (Element) element.selectSingleNode("servlet-name");
//				String servletName = servletnameElement.getStringValue();
//				Element servletclassElement = (Element) element.selectSingleNode("servlet-class");
//				String servletClass = servletclassElement.getStringValue();
//
//				// 根据servlet-name的值找到url-pattern
//				Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
//				// /yanliang
//				String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
//				servletMap.put(urlPattern, (HttpServlet) Class.forName(servletClass).newInstance());
//			}
//
//		} catch (DocumentException e) {
//			e.printStackTrace();
//		} catch (IllegalAccessException e) {
//			e.printStackTrace();
//		} catch (InstantiationException e) {
//			e.printStackTrace();
//		} catch (ClassNotFoundException e) {
//			e.printStackTrace();
//		}
//
//	}
//
//
//	/**
//	 * 启动入口
//	 * @param args
//	 */
//	public static void main(String[] args) {
////		// 1.0 版本启动
////		Bootstrap bootstrap = new Bootstrap();
////		try {
////			bootstrap.start1();
////		} catch (IOException e) {
////			e.printStackTrace();
////		}
//
//
////		// 2.0 版本启动
////		Bootstrap bootstrap = new Bootstrap();
////		try {
////			bootstrap.start2();
////		} catch (IOException e) {
////			e.printStackTrace();
////		}
//
////		// 3.0 版本启动
////		Bootstrap bootstrap = new Bootstrap();
////		try {
////			bootstrap.start3();
////		} catch (IOException e) {
////			e.printStackTrace();
////		} catch (Exception e) {
////			e.printStackTrace();
////		}
//
//		// 多线程改造版
//		Bootstrap bootstrap = new Bootstrap();
//		try {
//			bootstrap.start4();
//		} catch (IOException e) {
//			e.printStackTrace();
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//	}


	// -------------------------- Minicat 4.0 作业 ---------------------------
	private List<MyHost> hostList = new ArrayList<>();
	/**
	 * minicat启动需要初始化展开的一些操作
	 */
	public void start() throws Exception {

		loadServer();

		//定义线程池
		int corePoolSize = 10;
		int maximumPoolSize = 50;
		long keepAliveTime = 100L;
		TimeUnit unit = TimeUnit.SECONDS;
		BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(50);
		ThreadFactory threadFactory = Executors.defaultThreadFactory();
		RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
		ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
				keepAliveTime, unit, workQueue, threadFactory, handler);

		// 监听 port 端口
		ServerSocket serverSocket = new ServerSocket(port);
		System.out.println("==========>>>>Minicat start on port: " + port);

		/**
		 * 使用线程池
		 */
		while (true) {
			Socket socket = serverSocket.accept();
			RequestProcessor requestProcessor = new RequestProcessor(socket, hostList);
//			requestProcessor.start();
			threadPoolExecutor.execute(requestProcessor);
		}
	}

	/**
	 * 加载web.xml
	 */
	private void loadServlet(String path, MyContext context) {
		try {
			File file = new File(path + "/WEB-INF/web.xml");
			InputStream resourceAsStream = new FileInputStream(file);
			SAXReader saxReader = new SAXReader();
			Document document = saxReader.read(resourceAsStream);
			Element rootElement = document.getRootElement();
			List<Element> selectNodes = rootElement.selectNodes("//servlet");
			for (int i = 0; i < selectNodes.size(); i++) {
				Element element = selectNodes.get(i);
				Element servletnameElement = (Element) element.selectSingleNode("servlet-name");
				String servletname = servletnameElement.getStringValue();
				Element servletclassElement = (Element) element.selectSingleNode("servlet-class");
				String servletclass = servletclassElement.getStringValue();

				Element servletMapping = (Element) rootElement.selectSingleNode(
						"/web-app/servlet-mapping[servlet-name='" + servletname + "']");
				String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();

				MyWrapper wrapper = new MyWrapper(urlPattern, (HttpServlet) Class.forName(servletclass).newInstance());
				context.setWrapper(wrapper);
			}
		} catch (DocumentException | ClassNotFoundException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 加载server.xml
	 */
	private void loadServer() {
		InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
		SAXReader saxReader = new SAXReader();
		try {
			Document document = saxReader.read(resourceAsStream);
			Element rootElement = document.getRootElement();
			List<Element> selectNodes = rootElement.selectNodes("//Server");
			if (selectNodes == null || selectNodes.size() == 0) {
				return;
			}
			List<MyHost> hosts = new ArrayList<>();
			for (int i = 0; i < selectNodes.size(); i++) {
				Element element = selectNodes.get(i);
				Element serviceElement = (Element) element.selectSingleNode("Service");
				Element connector = (Element) serviceElement.selectSingleNode("Connector");
				port = Integer.parseInt(connector.attribute("port").getValue());

				Element engineElement = (Element) connector.selectSingleNode("Engine");
				Element hostElement = (Element) engineElement.selectSingleNode("Host");
				String hostName = hostElement.attribute("name").getValue();

				String appBasePath = hostElement.attribute("appBase").getValue();
				List<MyContext> contexts = new ArrayList<>();
				File file = new File(appBasePath);
				//解析文件，获取servlet以及url-pattern
				if (file.exists()) {
					File[] files = file.listFiles();
					if (files == null || files.length == 0) {
						return;
					}
					for (File f : files) {
						if (f.isDirectory()) {
							//demo1/demo2文件夹
							MyContext mappedContext = new MyContext(f.getName(),
									f.getAbsolutePath());
							loadServlet(f.getAbsolutePath(), mappedContext);
							contexts.add(mappedContext);
						}
					}
				}
				//封装host
				MyHost mappedHost = new MyHost(hostName, appBasePath, contexts);
				hosts.add(mappedHost);
			}
			hostList.addAll(hosts);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		Bootstrap bootstrap = new Bootstrap();
		try {
			bootstrap.start();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}
